Skip to content

Introduce splice-compatible commitment update monitor variants #3855

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

wpaulino
Copy link
Contributor

@wpaulino wpaulino commented Jun 12, 2025

No description provided.

@ldk-reviews-bot
Copy link

ldk-reviews-bot commented Jun 12, 2025

👋 Thanks for assigning @tankyleo as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

@wpaulino wpaulino requested a review from tankyleo June 12, 2025 21:43
Comment on lines 3207 to 3209
let htlcs_for_commitment = |commitment: &CommitmentTransaction| {
let mut nondust_htlcs = commitment.nondust_htlcs().clone().into_iter();
let mut sources = htlc_data.nondust_htlc_sources.clone().into_iter();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too happy with this, but trying to not duplicatively track the HTLC sources across FundingScopes is a good bit of non-trivial work. At least they'll only exist in the current and previous counterparty commitments, but those are still per FundingScope. The simplest thing we could do for now is Arc them to reduce memory bandwidth (unfortunately on disk we'll still have duplicates), but I chose not to pursue that unless we're sure of it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given its just for the latest and prev commitment txn I feel like its okay. It also gives us room to relax the restriction on multiple splices having the same dust/non-dust HTLC sets in the future.

@wpaulino wpaulino requested a review from TheBlueMatt June 12, 2025 21:48
Copy link

codecov bot commented Jun 13, 2025

Codecov Report

Attention: Patch coverage is 50.93750% with 157 lines in your changes missing coverage. Please review.

Project coverage is 88.80%. Comparing base (c48e0a8) to head (4dc47f9).
Report is 43 commits behind head on main.

Files with missing lines Patch % Lines
lightning/src/chain/channelmonitor.rs 50.71% 96 Missing and 8 partials ⚠️
lightning/src/ln/channel.rs 50.00% 53 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3855      +/-   ##
==========================================
- Coverage   89.65%   88.80%   -0.86%     
==========================================
  Files         164      165       +1     
  Lines      134658   119288   -15370     
  Branches   134658   119288   -15370     
==========================================
- Hits       120734   105937   -14797     
+ Misses      11246    11020     -226     
+ Partials     2678     2331     -347     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@tankyleo tankyleo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks dude, just went through the first commit, will continue tomorrow. I have a big-picture question in commitment_signed_batch take a look at that first.

let msg = messages
.get(&funding_txid)
.ok_or_else(|| ChannelError::close(format!("Peer did not send a commitment_signed for pending splice transaction: {}", funding_txid)))?;
let (commitment_tx, htlcs_included) = self.context.validate_commitment_signed(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might not be worth the pain let me know:

Can we avoid doing the work of populating and sorting this table for all the pending scopes in build_commitment_transaction ? We only need it for the current scope here.

(In validate_commitment_signed, let's read the HTLCs from the commitment transaction instead of the HTLC-source table).

Also wondering if we can make the state and dust-vs-nondust HTLC sorting only once for all scopes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm yeah this would be nice, this code was mostly written before we made the change to populate the source table separately. I wouldn't consider it a blocker to this PR, unless @TheBlueMatt feels strongly.

Copy link
Contributor

@tankyleo tankyleo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went through the second commit, some similar questions, some new ones.

@@ -3175,11 +3171,11 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
self.counterparty_hash_commitment_number.insert(htlc.payment_hash, commitment_number);
}

log_trace!(logger, "Tracking new counterparty commitment transaction with txid {} at commitment number {} with {} HTLC outputs", txid, commitment_number, htlc_outputs.len());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You find this log not necessary ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wpaulino just want to confirm here - i think the worry is hey these could be used to cheat so make sure we are tracking them ?

@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @TheBlueMatt! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@ldk-reviews-bot
Copy link

🔔 2nd Reminder

Hey @TheBlueMatt! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

Comment on lines 3207 to 3209
let htlcs_for_commitment = |commitment: &CommitmentTransaction| {
let mut nondust_htlcs = commitment.nondust_htlcs().clone().into_iter();
let mut sources = htlc_data.nondust_htlc_sources.clone().into_iter();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given its just for the latest and prev commitment txn I feel like its okay. It also gives us room to relax the restriction on multiple splices having the same dust/non-dust HTLC sets in the future.

Copy link
Contributor

@tankyleo tankyleo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another pass on the first commit, will continue first thing tomorrow...

Copy link
Contributor

@tankyleo tankyleo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done with the two other commits

@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @TheBlueMatt! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@TheBlueMatt
Copy link
Collaborator

Mind addressing @tankyleo's feedback?

@TheBlueMatt TheBlueMatt removed their request for review June 27, 2025 19:16
wpaulino added 3 commits June 27, 2025 14:52
This new variant is a backwards-incompatible successor to
`LatestHolderCommitmentTXInfo` that is capable of handling holder
commitment updates while a splice is pending. Since all holder
commitment candidates share the same set of non-dust and dust HTLCs
(though each non-dust HTLC can have differing output indices), we can
share the same set of HTLC source data across all candidates.
This new variant is a backwards-incompatible successor to
`LatestCounterpartyCommitmentTXInfo` that is capable of handling
counterparty commitment updates while a splice is pending. Since all
counterparty commitment candidates share the same set of non-dust and
dust HTLCs (though each non-dust HTLC can have differing output
indices), we can share the same set of HTLC source data across all
candidates. Unfortunately, each `FundingScope` tracks its own set of
`counterparty_claimable_outpoints`, which includes the HTLC source data
(though only for the current and previous counterparty commitments), so
we end up duplicating it (both in memory and on disk) temporarily.
They don't need to be tracked as we can recompute them easily, though we
still write them in the `ChannelMonitor` for the current `FundingScope`
for backwards compatibility. The serialization implementation for
`FundingScope` can now use the `impl_writeable_tlv_based` macro as a
result.
@wpaulino wpaulino force-pushed the splice-commitment-monitor-update branch from 0e88cdf to 4dc47f9 Compare June 27, 2025 21:54
@wpaulino wpaulino requested review from TheBlueMatt and tankyleo June 27, 2025 21:55
fn update_counterparty_commitment_data(
&mut self, commitment_txs: &[CommitmentTransaction], htlc_data: &CommitmentHTLCData,
) -> Result<(), &'static str> {
self.verify_matching_commitment_transactions(commitment_txs.iter())?;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function verify_matching_commitment_transactions returns a Result, but the error case isn't being handled here. Consider propagating the error back to the caller by changing this to:

self.verify_matching_commitment_transactions(commitment_txs.iter())?;

This matches the pattern used in update_holder_commitment_data and ensures errors aren't silently ignored.

Spotted by Diamond

Is this helpful? React 👍 or 👎 to let us know.

@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @TheBlueMatt @tankyleo! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

1 similar comment
@ldk-reviews-bot
Copy link

🔔 1st Reminder

Hey @TheBlueMatt @tankyleo! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.


let current_funding_commitment_tx = commitment_txs.first().unwrap();
self.current_holder_commitment_number = current_funding_commitment_tx.commitment_number();
self.onchain_tx_handler.provide_latest_holder_tx(current_funding_commitment_tx.clone());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mind leaving a comment here on why OnchainTxHandler doesn't need to know about other commitments?

let source = (!htlc.offered).then(|| {
let source = sources
.next()
.expect("Every inbound non-dust HTLC should have a corresponding source")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally call these "outbound" HTLCs, since they're outbound, just !offered on the commitment tx.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes my bad should be every outbound :)

Copy link
Contributor

@tankyleo tankyleo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing blocking, just have a pending question further above about why we delete

log_trace!(logger, "Tracking new counterparty commitment transaction with txid {} at commitment number {} with {} HTLC outputs", txid, commitment_number, htlc_outputs.len());

@TheBlueMatt
Copy link
Collaborator

Landing this, we can figure out the logging and comments in a followup.

@TheBlueMatt TheBlueMatt merged commit 34664bc into lightningdevkit:main Jul 1, 2025
26 of 28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

4 participants